package com.lixinlei.meetingfilm.apigwzuul.filters;

import com.alibaba.fastjson.JSONObject;
import com.lixinlei.meetingfilm.utils.common.vo.BaseResponseVO;
import com.lixinlei.meetingfilm.utils.properties.JwtProperties;
import com.lixinlei.meetingfilm.utils.util.JwtTokenUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;

@Slf4j
public class JWTFilter extends ZuulFilter {

    /**
     * Filter类型
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * filter的执行顺序
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否要拦截
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * Filter 的具体业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {

        // JWT工具类
        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
        JwtProperties jwtProperties = JwtProperties.getJwtProperties();

        // ThreadLocal
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();

        // 提前设置请求继续，如果失败则修改此内容
        ctx.setSendZuulResponse(true);
        ctx.setResponseStatusCode(200);

        // 判断是否是登陆请求，如果是登陆请求则不验证 JWT
        if (request.getServletPath().endsWith("/" + jwtProperties.getAuthPath())) {
            // 返回 null，就相当于让请求通行了
            return null;
        }

        // 1、根据 Token 验证用户是否登录过
        // Token 存放在 Header 的 Authorization 字段中
        final String requestHeader = request.getHeader(jwtProperties.getHeader());
        String authToken = null;
        // Header 的 Authorization 字段中存放的 Token 是形如 “Bearer header.payload.sign” 格式的
        if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
            authToken = requestHeader.substring(7);

            //验证 token 是否过期,包含了验证 jwt 是否正确
            try {
                boolean flag = jwtTokenUtil.isTokenExpired(authToken);
                if (flag) {
                    // Token 过期，返回客户端
                    renderJson(ctx , response, BaseResponseVO.noLogin());
                } else {
                    // 2、解析出 JWT 的 payload 中的 userid 和 randomkey
                    String randomkey = jwtTokenUtil.getMd5KeyFromToken(authToken);
                    String userId = jwtTokenUtil.getUsernameFromToken(authToken);
                    // 3、是否需要验签，以及验签的算法

                    // 4、判断 userid 是否有效
                    // TODO
                }
            } catch (JwtException e) {
                //有异常就是 token 解析失败
                renderJson(ctx ,response, BaseResponseVO.noLogin());
            }
        } else {
            // header 没有带 Bearer 字段
            renderJson(ctx ,response, BaseResponseVO.noLogin());
        }

        // 返回 null，就相当于让请求通行了
        return null;
    }

    /**
     * 渲染 json 对象
     */
    public static void renderJson(RequestContext ctx, HttpServletResponse response, Object jsonObject) {
        // 设置终止请求
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        ctx.setSendZuulResponse(false);
        ctx.setResponseBody(JSONObject.toJSONString(jsonObject));
    }

}
